﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

using Job.Core.Common;

namespace Job.Core.Threading.Task
{
    /// <summary>
    /// 代表一个工作任务。
    /// </summary>
    public class TaskJob
    {
        #region Properties

        /// <summary>
        /// 任务名称。
        /// </summary>
        public string TaskName { get; set; }

        /// <summary>
        /// 任务执行者。
        /// </summary>
        public ITaskExecuter TaskExecuter { get; set; }

        /// <summary>
        /// 执行参数。
        /// </summary>
        public object[] Params { get; set; }

        /// <summary>
        /// 开始时间。
        /// </summary>
        public DateTime StartTime { get; set; }

        /// <summary>
        /// 循环周期。
        /// </summary>
        public int? Period { get; set; }

        /// <summary>
        /// 循环次数。
        /// </summary>
        public int? Repeat { get; set; }

        /// <summary>
        /// 周期单位。
        /// </summary>
        public PeriodType PeriodType { get; set; }

        /// <summary>
        /// 日记记录器。
        /// </summary>
        public ILogger Logger { get; set; }

        /// <summary>
        /// 已执行次数。
        /// </summary>
        public int RunCount { get; private set; }

        /// <summary>
        /// 最后执行时间。
        /// </summary>
        public DateTime? LastRunTime { get; private set; }

        /// <summary>
        /// 是否正在运行中。
        /// </summary>
        public bool Running { get; private set; }

        #endregion

        #region Methods

        /// <summary>
        /// 判断是否应该在指定时间点上执行任务。
        /// </summary>
        /// <param name="time">指定时间。</param>
        /// <returns>是返回 true，否则返回 false。</returns>
        public virtual bool IsOnTime(DateTime time)
        {
            //还没达到开始时间。
            if (time < StartTime)
                return false;

            //已达到指定的运行次数。
            if (Repeat.HasValue && RunCount >= Repeat.Value)                          
                return false;

            //仅执行一次的情况。
            if (PeriodType == PeriodType.None && RunCount == 0)
                return true;

            int t = RunCount * Period.Value;

            switch (PeriodType)
            {
                case PeriodType.Millisecond:
                    return (time - StartTime).TotalMilliseconds > t;
                case PeriodType.Seconds:                   
                    return (time - StartTime).TotalSeconds > t;
                case PeriodType.Minutes:
                    return (time - StartTime).TotalMinutes > t;
                case PeriodType.Hours:
                    return (time - StartTime).TotalHours > t;
                case PeriodType.Days:
                    return (time - StartTime).TotalDays > t;
                case PeriodType.Weeks:
                    return (time - StartTime).TotalDays * 7 > t;
                case PeriodType.Months:
                    int months = 0;
                    DateTime mdt = StartTime;
                    while (mdt < time)
                    {
                        mdt = mdt.AddMonths(1);
                        months++;
                    }
                    return months > t;
                case PeriodType.Years:
                    int years = 0;
                    DateTime ydt = StartTime;
                    while (ydt < time)
                    {
                        ydt = ydt.AddYears(1);
                        years++;
                    }
                    return years > t;
            }

            return false;
        }

        /// <summary>
        /// 执行任务。
        /// <param name="time">执行任务的时间。</param>
        /// </summary>
        public virtual void Execute(DateTime time)
        {
            Running = true;

            try
            {
                TaskExecuter.Execute(Params);
            }
            catch (Exception e)
            {
                //如果设置了日志记录器，将记录错误日志。
                if (Logger != null)
                    Logger.Log(e);
            }
            finally
            {
                RunCount++;
                Running = false;
                LastRunTime = time;
            }
        }

        #endregion
    }
}